package Cliente.interface_grafico;

import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.util.Iterator;
import java.util.LinkedList;

import baralho.carta.Carta;
import baralho.carta.Naipe;

public class MonteCartasUI {

	private LinkedList<CartaUI> cartas;
	private Orientacao orientacao;
	private Point inicio;
	private String nome;
	private boolean esta_a_jogar;
	private static final int espaco_h = -60;
	private static final int espaco_v = -100;
	public MesaGrafica mesa;

	/**
	 * 
	 * @param inicio: indica onde o monte de cartas deve comecar
	 * @param o: indica a orientacao do monte de cartas (horizontal ou vertical)
	 */
	public MonteCartasUI(String nome, Point inicio, Orientacao o, MesaGrafica mesa){
		assert (o != null && inicio != null && nome != null);
		this.nome = nome;
		this.orientacao = o;
		this.inicio = inicio;
		this.cartas = new LinkedList<CartaUI>();
		this.esta_a_jogar = false;
		this.mesa = mesa;
	}

	public synchronized void adicionaCarta(CartaUI carta){
		this.cartas.add(carta);
	}

	/**
	 * Tira a carta especificada no argumento.
	 * 
	 * @param c: a carta que deve ser retirada.
	 * @return
	 * retorna a representacao da carta no GUI (CartaUI)
	 */
	public synchronized CartaUI tiraCarta(Carta c){
		if(c == null){
			return this.cartas.removeLast();
		}
		
		
		CartaUI result = null;
		Iterator<CartaUI> iter = this.cartas.iterator();
		boolean tirou = false;
		while(iter.hasNext()){
			CartaUI carta = iter.next();
			if(carta.getCarta().equals(c) && !tirou){
				tirou = true;
				iter.remove();
				result = carta;
				if(iter.hasNext()){
					carta = iter.next();
				}
			}

			//Encostar as restantes cartas
			if(tirou == true){
				if(carta.getNivel() > 1) carta.setNivel(carta.getNivel() - 1);	//baixar o nivel da carta
				if(orientacao == Orientacao.HORIZONTAL){
					carta.moveTo(new Point(carta.getX() - carta.getWidth() - espaco_h, carta.getY()), mesa);
				}else{
					carta.moveTo(new Point(carta.getX(), carta.getY() - carta.getHeight() - espaco_v), mesa);
				}
			}
		}
		return result;
	}
	
	/**
	 * Tira a ultima carta do monte.
	 * @return: Devolve a ultima carta no Monte (Tipo CartaUI).
	 */
	public synchronized CartaUI tiraUltimaCarta(){
		return this.cartas.removeLast();
	}

	/**
	 * Devolve a posiciao na qual a proxima carta deve ser inserida.
	 * 
	 * @return Retorna o ponto como Point.
	 */
	public  synchronized Point getPosicaoProximaCarta(){
		if(this.cartas.isEmpty()){
			return this.inicio;
		}else if(this.orientacao == Orientacao.HORIZONTAL){
			return (new Point(this.cartas.getLast().getX() + this.cartas.getLast().getWidth() + espaco_h, this.cartas.getLast().getY()));
		}else if(this.orientacao == Orientacao.MESA){
			return this.inicio;
		}else{
			return (new Point(this.cartas.getLast().getX(), this.cartas.getLast().getY() + this.cartas.getLast().getHeight() + espaco_v));
		}
	}
	
	public synchronized int getNivelProximaCarta(){
		if(!this.cartas.isEmpty()){
			return this.cartas.getLast().getNivel() + 1;
		}
		return 1;
	}

	public String getNome() {
		return nome;
	}

	public synchronized void paint(Graphics g) {
		if(!this.cartas.isEmpty()){
			if(this.esta_a_jogar)
			paintBrilho((Graphics2D)g, 20);
			
			g.setColor(Color.black);
			g.setFont(new Font("Arial Bold", Font.ITALIC, 16));
			g.drawString(this.nome, this.inicio.x, this.inicio.y);
			
			Iterator<CartaUI> iter = this.cartas.iterator();
			while(iter.hasNext()){
				iter.next().paint(g);
			}
		}
	}

	public synchronized void setLocation(Point d) {
		int dx = d.x - this.inicio.x;
		int dy = d.y - this.inicio.y;
		this.inicio = d;
		Iterator<CartaUI> iter = this.cartas.iterator();
		CartaUI carta = null;
		for(int i=0; i<this.cartas.size(); i++){
			carta = iter.next();
			carta.setLocation(carta.getX() + dx, carta.getY() + dy);
		}
	}

	public synchronized CartaUI getCardAt(Point point) {
		Iterator<CartaUI> iter = this.cartas.iterator();
		LinkedList<CartaUI> clicked_cards = new LinkedList<CartaUI>();
		CartaUI carta = null;
		while(iter.hasNext()){
			carta = iter.next();
			if(carta.noPonto(point)){
				clicked_cards.addLast(carta);
			}
		}
		carta = null;
		for(CartaUI c: clicked_cards){
			if(carta!=null && c.getNivel() > carta.getNivel()){
				carta = c;
			}else if(carta == null){
				carta = c;
			}
		}
		return carta;
	}

	public int getNumCartas() {
		return this.cartas.size();
	}

	public Point getInicio() {
		return this.inicio;
	}

	public boolean soTemCopas() {
		for(CartaUI c: this.cartas){
			if(c.getCarta().getNaipe() != Naipe.Copas){
				return false;
			}
		}
		return true;
	}
	
	private void paintBrilho(Graphics2D g2d, int width) {
		float alpha = 0.05f;
		AlphaComposite myAlpha = AlphaComposite.getInstance(AlphaComposite.XOR, alpha);

		//Desenha varias vezes a volta da carta (rectangulo) e sobrepoe molduras cada vez menores.
	    int double_width = width*2;	// g2d.drawRoundRect(...) desenha molduras que estao meio por fora e meio por dentro do rectangulo. Por isso o tamanho e duplicado para o tamanho visto (nao tapado pela carta) ser o indicado.
	    for (int i=double_width; i >= 2; i-=2) {
	    	myAlpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha);
			g2d.setComposite(myAlpha);
			
	        g2d.setColor(Color.lightGray);
	        g2d.setStroke(new BasicStroke(i));
	        g2d.drawRoundRect(this.inicio.x, this.inicio.y, this.cartas.getLast().getX()+this.cartas.getLast().getWidth()-this.inicio.x, this.cartas.getLast().getY()+this.cartas.getLast().getHeight()-this.inicio.y, 10, 10);
	    }
	    myAlpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER,1.0f);
		g2d.setComposite(myAlpha);
	}

	public void setEstaAJogar(boolean esta_a_jogar) {
		this.esta_a_jogar = esta_a_jogar;
	}
	
	
	public void setNome(String nome){
		this.nome = nome;
	}
	
	
	
}